
package com.hlkj.pay.app.order.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.math.BigDecimal;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.impl.CommonChannelCallHandler;
import com.hlkj.pay.app.order.IWithdrawOrderAppService;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.MerchantResultCode;
import com.hlkj.pay.common.OpenApiResultCode;
import com.hlkj.pay.common.PayResultCode;
import com.hlkj.pay.dto.LocalMerchantRequest;
import com.hlkj.pay.dto.order.NotifyOrderWithdrawDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.gateway.order.IChannelWithdrawGateway;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.OrderWithdrawDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.service.merchant.IMerchantApplicationService;
import com.hlkj.pay.service.merchant.IMerchantService;
import com.hlkj.pay.service.order.IWithdrawOrderService;
import com.hlkj.pay.service.pay.IProviderService;
import com.hlkj.pay.util.OrderCodeUtil;
import com.hlkj.pay.vo.openapi.order.req.OpenApiOrderQueryReq;
import com.hlkj.pay.vo.openapi.order.req.OpenApiOrderWithdrawReq;
import com.hlkj.pay.vo.openapi.order.resp.OpenApiOrderWithdrawResp;
import com.hlkj.pay.vo.order.req.OrderWithdrawReq;
import com.hlkj.pay.vo.order.resp.OrderWithdrawResp;

import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2025/02/08 15:21
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Validated
public class WithdrawOrderAppServiceImpl implements IWithdrawOrderAppService {

    private final IProviderService providerService;

    private final IChannelWithdrawGateway channelWithdrawGateway;

    private final CommonChannelCallHandler commonChannelCallHandler;

    private final IWithdrawOrderService withdrawOrderService;

    private final IMerchantService merchantService;

    private final OrderHandler orderHandler;

    private final OrderCodeUtil orderCodeUtil;

    private final IMerchantApplicationService merchantApplicationService;

    @Override
    public String orderStatusCallBack(String channelCode, String providerCode, HttpServletRequest request) {
        // 获取通道配置
        ProviderChannelConfigDO providerChannelConfigDO = providerService.queryConfig(providerCode, channelCode);
        if (providerChannelConfigDO == null) {
            return processOrderCallBackErrorResponse(channelCode, providerCode, null, null, CommonResult.error(PayResultCode.PROVIDER_CHANNEL_NOT_EXITS));
        }
        CommonResult<NotifyOrderWithdrawDto> commonResult = channelWithdrawGateway.orderStatusParse(request, providerChannelConfigDO);
        if (!commonResult.isSuccess()) {
            if (MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode().equals(commonResult.getCode())) {
                NotifyOrderWithdrawDto notifyOrderTransferDto = commonResult.getData();
                if (notifyOrderTransferDto != null && StringUtils.hasText(notifyOrderTransferDto.getPayOrderNo())
                        && MerchantEnum.PROCESS_STATUS.SUCCESS.getCode().equals(notifyOrderTransferDto.getStatus().getCode())) {
                    OrderWithdrawDO orderTransferDO = withdrawOrderService.queryPayOrder(notifyOrderTransferDto.getPayOrderNo());
                    if (orderTransferDO == null) {
                        log.info("收到提现订单回调,签名错误,通过回调订单查询订单数据不存在 payOrderNo:{}", notifyOrderTransferDto.getPayOrderNo());
                        return commonResult.getMsg();
                    }
                    log.info("收到提现订单回调,签名错误,通过回调订单回查第三方支付状态 payOrderNo:{}", notifyOrderTransferDto.getPayOrderNo());
                    queryPayStatus(orderTransferDO);
                    return processOrderCallBackSuccessResponse(channelCode, orderTransferDO, notifyOrderTransferDto.getCallBackBody(), CommonResult.success(),
                            providerChannelConfigDO);
                }
                else {
                    return commonResult.getMsg();
                }
            }
            return commonResult.getMsg();
        }
        return processCallBack(channelCode, commonResult.getData(), providerChannelConfigDO);
    }

    @Override
    public CommonResult<OpenApiOrderWithdrawResp> submitOrder(@Valid OpenApiOrderWithdrawReq orderWithdrawReq) {
        log.info("orderWithdraw submitOrder orderTransferReq:{}", JsonUtils.toJsonString(orderWithdrawReq));
        try {
            LocalMerchantRequest localMerchantRequest = (LocalMerchantRequest) LocalContext.get();
            if (StringUtils.isEmpty(orderWithdrawReq.getMchOrderNo())) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(orderWithdrawReq.getMchChannelCode());
            if (merchantAppChannelDO == null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_APP_CHANNEL_NOT_EXIST);
            }
            OrderWithdrawDO orderWithdrawDO = withdrawOrderService.queryByMchOrderNo(localMerchantRequest.getSn(), orderWithdrawReq.getMchOrderNo());
            if (orderWithdrawDO != null) {
                return CommonResult.error(OpenApiResultCode.DATA_HAS_EXIST);
            }
            boolean extensionExist = channelWithdrawGateway.extensionExist(merchantAppChannelDO.getChannelCode());
            if (!extensionExist) {
                return CommonResult.error(CommonResultCode.EXTENSION_NOT_EXIST);
            }
            OrderWithdrawDO orderTransfer = BeanUtil.copyProperties(orderWithdrawReq, OrderWithdrawDO.class);
            orderTransfer.setSn(localMerchantRequest.getSn());
            orderTransfer.setPayOrderNo(orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.WITHDRAW));
            orderTransfer.setStatus(MerchantEnum.PROCESS_STATUS.INIT.getCode());
            orderTransfer.setAppId(localMerchantRequest.getAppId());
            orderTransfer.setSignType(localMerchantRequest.getSignType());
            orderTransfer.setProviderCode(merchantAppChannelDO.getProviderCode());
            orderTransfer.setChannelCode(merchantAppChannelDO.getChannelCode());
            CommonResult<OrderWithdrawDO> commonResult = channelWithdrawGateway.submitWithdrawOrder(merchantAppChannelDO, orderTransfer);
            if (!commonResult.isSuccess()) {
                return CommonResult.error(commonResult.getCode(), commonResult.getMsg());
            }
            OrderWithdrawDO updateOrderTransfer = commonResult.getData();
            if (updateOrderTransfer != null) {
                orderTransfer.setRemark(updateOrderTransfer.getRemark());
                orderTransfer.setMessage(updateOrderTransfer.getMessage());
                orderTransfer.setStatus(updateOrderTransfer.getStatus());
                orderTransfer.setBankCardId(updateOrderTransfer.getBankCardId());
                orderTransfer.setUserId(updateOrderTransfer.getUserId());
            }
            withdrawOrderService.addWithdrawOrder(orderTransfer);
            return CommonResult.success(BeanUtil.copyProperties(orderTransfer, OpenApiOrderWithdrawResp.class));
        }
        catch (Exception e) {
            log.error("orderWithdraw submitOrder  error:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<OrderWithdrawResp> submitOrder(OrderWithdrawReq orderWithdrawReq) {
        log.info("admin orderWithdraw submitOrder orderTransferReq:{}", JsonUtils.toJsonString(orderWithdrawReq));
        try {
            MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(orderWithdrawReq.getMchChannelCode());
            if (merchantAppChannelDO == null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_APP_CHANNEL_NOT_EXIST);
            }
            boolean extensionExist = channelWithdrawGateway.extensionExist(merchantAppChannelDO.getChannelCode());
            if (!extensionExist) {
                return CommonResult.error(CommonResultCode.EXTENSION_NOT_EXIST);
            }

            BigDecimal feeAmount = merchantService.queryMerchantFeeAmount(merchantAppChannelDO.getSn());
            if(feeAmount == null || feeAmount.doubleValue()  <= 0){
                return CommonResult.error(OpenApiResultCode.MERCHANT_CHANNEL_BALANCE_NOT_ENOUGH);
            }

            OrderWithdrawDO orderTransfer = BeanUtil.copyProperties(orderWithdrawReq, OrderWithdrawDO.class);
            orderTransfer.setSn(merchantAppChannelDO.getSn());
            orderTransfer.setPayOrderNo(orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.WITHDRAW));
            orderTransfer.setStatus(MerchantEnum.PROCESS_STATUS.INIT.getCode());
            orderTransfer.setAppId(merchantAppChannelDO.getAppId());
            orderTransfer.setProviderCode(merchantAppChannelDO.getProviderCode());
            orderTransfer.setChannelCode(merchantAppChannelDO.getChannelCode());
            CommonResult<OrderWithdrawDO> commonResult = channelWithdrawGateway.submitWithdrawOrder(merchantAppChannelDO, orderTransfer);
            if (!commonResult.isSuccess()) {
                return CommonResult.error(commonResult.getCode(), commonResult.getMsg());
            }
            OrderWithdrawDO updateOrderTransfer = commonResult.getData();
            if (updateOrderTransfer != null) {
                orderTransfer.setRemark(updateOrderTransfer.getRemark());
                orderTransfer.setMessage(updateOrderTransfer.getMessage());
                orderTransfer.setStatus(updateOrderTransfer.getStatus());
                orderTransfer.setBankCardId(updateOrderTransfer.getBankCardId());
                orderTransfer.setUserId(updateOrderTransfer.getUserId());
            }
            withdrawOrderService.addWithdrawOrder(orderTransfer);
            return CommonResult.success(BeanUtil.copyProperties(orderTransfer, OrderWithdrawResp.class));
        }
        catch (Exception e) {
            log.error("admin orderWithdraw submitOrder  error:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<OpenApiOrderWithdrawResp> queryOrder(OpenApiOrderQueryReq orderQueryReq) {
        log.info("orderWithdraw queryOrder orderQueryReq:{}", JsonUtils.toJsonString(orderQueryReq));
        try {
            LocalMerchantRequest localMerchantRequest = (LocalMerchantRequest) LocalContext.get();
            if (StringUtils.isEmpty(orderQueryReq.getPayOrderNo()) && StringUtils.isEmpty(orderQueryReq.getMchOrderNo())) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            OrderWithdrawDO orderWithdraw;
            if (StringUtils.hasText(orderQueryReq.getPayOrderNo())) {
                orderWithdraw = withdrawOrderService.queryPayOrder(orderQueryReq.getPayOrderNo());
            }
            else {
                orderWithdraw = withdrawOrderService.queryByMchOrderNo(localMerchantRequest.getSn(), orderQueryReq.getMchOrderNo());
            }
            if (orderWithdraw == null) {
                return CommonResult.error(OpenApiResultCode.DATA_NOT_EXIST);
            }
            if (!orderWithdraw.getSn().equals(localMerchantRequest.getSn())) {
                return CommonResult.error(OpenApiResultCode.DATA_NOT_EXIST);
            }
            MerchantEnum.PROCESS_STATUS processStatus = MerchantEnum.PROCESS_STATUS.from(orderWithdraw.getStatus());

            switch (processStatus) {
                case SUCCESS:
                case FAIL:
                    break;
                default:
                    // 需要同步状态
                    queryPayStatus(orderWithdraw);
            }
            return CommonResult.success(BeanUtil.copyProperties(orderWithdraw, OpenApiOrderWithdrawResp.class));
        }
        catch (Exception e) {
            log.error("orderWithdraw queryOrder error:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    String processOrderCallBackSuccessResponse(String channelCode, OrderWithdrawDO orderWithdrawDO, String callBackBody, CommonResult commonResult,
            ProviderChannelConfigDO providerChannelConfigDO) {
        if (orderWithdrawDO != null) {
            LocalMerchantRequest localMerchantRequest = (LocalMerchantRequest) LocalContext.get();
            localMerchantRequest.setProviderCode(orderWithdrawDO.getProviderCode());
            localMerchantRequest.setChannelCode(orderWithdrawDO.getChannelCode());
            localMerchantRequest.setMchChannelCode(orderWithdrawDO.getMchChannelCode());
            localMerchantRequest.setSn(orderWithdrawDO.getSn());
            localMerchantRequest.setAppId(orderWithdrawDO.getAppId());
            LocalContext.set(localMerchantRequest);
        }
        commonResult.setData(providerChannelConfigDO);
        return commonChannelCallHandler.processWithdrawLogAndResponse(channelCode, orderWithdrawDO.getProviderCode(), orderWithdrawDO.getPayOrderNo(), callBackBody, commonResult);
    }

    String processOrderCallBackErrorResponse(String channelCode, String providerCode, String requestId, String callBackBody, CommonResult commonResult) {
        return commonChannelCallHandler.processWithdrawLogAndResponse(channelCode, providerCode, requestId, callBackBody, commonResult);
    }

    String processCallBack(String channelCode, NotifyOrderWithdrawDto notifyOrderWithdrawDto, ProviderChannelConfigDO providerChannelConfigDO) {
        OrderWithdrawDO orderWithdrawDb = withdrawOrderService.queryPayOrder(notifyOrderWithdrawDto.getPayOrderNo());
        if (orderWithdrawDb == null || !StringUtils.hasText(orderWithdrawDb.getPayOrderNo()) || orderWithdrawDb.getStatus() == null) {
            return processOrderCallBackErrorResponse(channelCode, providerChannelConfigDO.getProviderCode(), notifyOrderWithdrawDto.getPayOrderNo(),
                    notifyOrderWithdrawDto.getCallBackBody(), CommonResult.error(CommonResultCode.PARAMETER_MISSING));
        }
        if (orderWithdrawDb.getStatus().equals(notifyOrderWithdrawDto.getStatus().getCode())) {
            log.info("收到提现订单回调,订单实际状态与 回调状态一致 直接返回 payOrderNo:{}", orderWithdrawDb.getPayOrderNo());
            return processOrderCallBackSuccessResponse(channelCode, orderWithdrawDb, notifyOrderWithdrawDto.getCallBackBody(), CommonResult.success(), providerChannelConfigDO);
        }
        OrderWithdrawDO updatePayOrderDO = new OrderWithdrawDO();
        if (notifyOrderWithdrawDto.getSuccessTime() == null) {
            updatePayOrderDO.setSuccessTime(System.currentTimeMillis());
        }
        else {
            updatePayOrderDO.setSuccessTime(notifyOrderWithdrawDto.getSuccessTime());
        }
        updatePayOrderDO.setStatus(notifyOrderWithdrawDto.getStatus().getCode());
        updatePayOrderDO.setMessage(notifyOrderWithdrawDto.getMessage());
        if(!StringUtils.hasText(orderWithdrawDb.getChannelOrderNo())){
            updatePayOrderDO.setChannelOrderNo(notifyOrderWithdrawDto.getChannelOrderNo());
        }
        // 更新数据
        updatePayOrder(updatePayOrderDO, orderWithdrawDb);
        return processOrderCallBackSuccessResponse(channelCode, orderWithdrawDb, notifyOrderWithdrawDto.getCallBackBody(), CommonResult.success(), providerChannelConfigDO);
    }

    void updatePayOrder(OrderWithdrawDO updatePayOrderDO, OrderWithdrawDO payOrderDO) {
        if (MerchantEnum.PROCESS_STATUS.SUCCESS.getCode().equals(updatePayOrderDO.getStatus())) {
            updatePayOrderDO.setNotifyState(CommonEnum.YES_NO_TYPE.YES.getCode());
        }
        updatePayOrderDO.setId(payOrderDO.getId());
        int count = withdrawOrderService.updatePayOrderStatus(updatePayOrderDO);
        // 下发状态变更通知
        if (count > 0) {
            if (MerchantEnum.PROCESS_STATUS.SUCCESS.getCode().equals(updatePayOrderDO.getStatus())) {
                // 数据有更新 重新获取一次
                // payOrderDO = withdrawOrderService.queryPayOrder(payOrderDO.getPayOrderNo());
                // 订单通知

                orderHandler.sendWithdrawFeeCalculate(payOrderDO.getPayOrderNo());
            }
        }
        else {
            log.info("提现订单 更新订单状态,数据库返回更新的状态与原数据状态一致 直接返回 payOrderNo:{}", payOrderDO.getPayOrderNo());
        }
    }

    /**
     * 支付状态查询
     *
     * @param orderWithdrawDO
     * @return
     */
    @Override
    public boolean queryPayStatus(OrderWithdrawDO orderWithdrawDO) {
        log.info("提现订单 查询支付中状态 mchOrderNo:{},state:{}", orderWithdrawDO.getMchOrderNo(), orderWithdrawDO.getStatus());
        MerchantEnum.PROCESS_STATUS payOrderStatus = MerchantEnum.PROCESS_STATUS.from(orderWithdrawDO.getStatus());
        switch (payOrderStatus) {
            case DOING:
                boolean extensionExist = channelWithdrawGateway.extensionExist(orderWithdrawDO.getChannelCode());
                if (extensionExist) {
                    OrderWithdrawDO updatePayOrderDO = channelWithdrawGateway.queryChannelOrder(orderWithdrawDO);
                    if (updatePayOrderDO != null && updatePayOrderDO.getStatus() != null) {
                        // 二者数据不一致 需要更新数据
                        if (!updatePayOrderDO.getStatus().equals(orderWithdrawDO.getStatus())) {
                            // 更新后的熟悉进行复制
                            orderWithdrawDO.setChannelOrderNo(updatePayOrderDO.getChannelOrderNo());
                            orderWithdrawDO.setSuccessTime(updatePayOrderDO.getSuccessTime());
                            orderWithdrawDO.setStatus(updatePayOrderDO.getStatus());
                            updatePayOrder(updatePayOrderDO, orderWithdrawDO);
                            return false;
                        }
                    }
                    else {
                        return true;
                    }
                    break;
                }
                else {
                    log.info("提现订单 当前通道不支持渠道订单功能 channelCode:{}", orderWithdrawDO.getChannelCode());
                    return false;
                }

        }
        return false;
    }
}
